package com.lh.process.engine.context;

import com.lh.process.engine.model.InvokeMethod;
import com.lh.process.engine.node.ProcessorDefinition;
import com.lh.process.engine.node.ProcessorNode;
import com.lh.process.engine.process.DynamicProcessor;
import com.lh.process.engine.process.Processor;
import com.lh.process.engine.process.RollBackProcessor;
import com.lh.process.engine.util.ProcessorUtil;
import javafx.beans.binding.ObjectExpression;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

/**
 * @author: linghao
 * @since: 2022/10/20
 */
@Slf4j
public class ProcessContext {

    private final Map<String, Object> params = new HashMap<>();
    private final ProcessorDefinition processorDefinition;
    //存放回退节点
    private final Stack<RollBackProcessor> rollBackProcessorsStack = new Stack<>();

    public ProcessContext(ProcessorDefinition processorDefinition) {
        this.processorDefinition = processorDefinition;
    }

    public void set(String key,Object val){
        params.put(key,val);
    }

    public <T> T get(String key){
        return (T)params.get(key);
    }

    public void start(){
        log.info("process excute start");
        process(processorDefinition.getFirst());
        log.info("process excute end");
    }

    private void process(ProcessorNode node) {
        if (node == null) {
            return;
        }
        Processor processor = node.getProcessor();
        if(processor instanceof RollBackProcessor){
            rollBackProcessorsStack.push((RollBackProcessor)processor);
        }
        //执行本节点process
        try {
            processor.process(this);
        }catch (Exception e){
            RollBackProcessor rollbackProcessor = null;
            try {
                // 回滚前面的所有可回滚节点，按照所有节点的顺序倒叙回滚
                while(!rollBackProcessorsStack.empty()){
                    rollbackProcessor = rollBackProcessorsStack.pop();
                    rollbackProcessor.rollback(this);
                }
            }catch (Exception e1){
                log.error("流程节点在回滚过程中抛出异常，process={}, context={}",
                        rollbackProcessor.getName());
            }
            processor.caughtException(this,e);
        }
        //执行本节点的next
        ProcessorNode processorNode;
        Map<String, ProcessorNode> nextNodes = node.getNextNodes();
        if (nextNodes == null || nextNodes.isEmpty()) {
            return;
        }
        if(processor instanceof DynamicProcessor){
            DynamicProcessor dynamicProcessor = (DynamicProcessor)processor;
            String nextNodeId = dynamicProcessor.nextNodeId(this);
            if(!nextNodes.containsKey(nextNodeId)){
                throw new IllegalArgumentException("DynamicProcess can not find next node with id:" + nextNodeId);
            }
            processorNode = nextNodes.get(nextNodeId);
        }else{
            // 不是动态节点，每个节点只有一个后继节点
            processorNode = nextNodes.values().stream().findAny().get();
        }
        //同步异步执行
        if(InvokeMethod.SYNC.equals(node.getInvokeMethod())){
            log.info("同步执行："+processorNode.getName());
            process(processorNode);
        }else{
            log.info("异步执行："+processorNode.getName());
            //异步也可以在接口中定义线程池参数进行配置
            ProcessorUtil.excuteAsync(new Runnable() {
                @Override
                public void run() {
                    process(processorNode);
                }
            });
        }

    }

}
